/********************************** (C) COPYRIGHT *******************************
* File Name          : foc_windows.c
* Author             : nx666
* Version            : V1.0.0
* Date               : 2023/04/02
* Description        : 实现foc控制器与外界交互
*******************************************************************************/
/***********************************头文件区域***********************************/
#include "ch32f20x.h"
#include "driver.h"
#include "sampling.h"
#include "common_type.h"
#include "stdio.h"
#include "FreeRTOS.h"
#include "debug.h"
#include "foc.h"
#include "interact.h"
#include <string.h>
#include "sampling.h"


/***********************************宏定义区***********************************/


/******************************** *全局变量区**********************************/
float printMat[6] = {0};
static uInt8      msgTxBuf[LOG_TX_BUF_SIZE];
static uInt8      msgRxBuf[LOG_RX_BUF_SIZE];
static logSet gLogDev = {0};
extern u8 switchFlag;


 /*********************************************************************
 * @fn      foc_int2str
 *
 * @brief   int类型数据转为字符串.
 *
 * @param   num - int类型数据. str - 输出的字符串. radix - 进制
 *
 * @return  成功 - 字符串  失败 - null
 */
static char * foc_int2str(Int32 num,char *str,Int32 radix)
{
    char index[]="0123456789ABCDEF";//索引表
    uInt32 unum;           //存放要转换的整数的绝对值,转换的整数可能是负数
    int i=0,j,k;          //i用来指示设置字符串相应位，转换之后i其实就是字符串的长度；转换后顺序是逆序的，有正负的情况，k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。
    
    if ((radix != 16)&&(radix != 10))
    {
        return NULL;
    }
    if (!str)
    {
        return NULL;
    }

    //获取要转换的整数的绝对值
    if(radix==10&&num<0)        //要转换成十进制数并且是负数
    {
        unum=(uInt32)-num;    //将num的绝对值赋给unum
        str[i++]='-';           //在字符串最前面设置为'-'号，并且索引加1
    }
    else
    {
        unum=(uInt32)num;      //若是num为正，直接赋值给unum
    }
 
    //转换部分，注意转换后是逆序的
    do
    {
        str[i++]=index[unum % (uInt32)radix];   //取unum的最后一位，并设置为str对应位，指示索引加1
        unum /= radix;                          //unum去掉最后一位
 
    }while(unum);  
 
    str[i]='\0';         //在字符串最后添加'\0'字符
 
    //将顺序调整过来
    if(str[0]=='-')
    {
        k=1;            //如果是负数，符号不用调整，从符号后面开始调整
    }
    else
    {
        k=0;            //不是负数，全部都要调整
    }
 
    char temp;//临时变量，交换两个值时用到
    for(j=k;j<=(i-1)/2;j++) //头尾一一对称交换，i其实就是字符串的长度，索引最大值比长度少1
    {
        temp=str[j];        //头部赋值给临时变量
        str[j]=str[i-1+k-j];//尾部赋值给头部
        str[i-1+k-j]=temp;  //将临时变量的值(其实就是之前的头部值)赋给尾部
    }
 
    return str;//返回转换后的字符串
}

 /*********************************************************************
 * @fn      foc_showCurrent
 *
 * @brief   发生一帧电流数据
 *
 * @param   pSet - 保存电流数据
 *
 * @return  None
 */
Int32 foc_showCurrent(sampling_ *pSet)
{
    char *msg[4] = {" id:\0"," aCur:\0"," bCur:\0"," cCur:\0",};
    char bufT[32] = {" id:\0"};
    Int32 val[4] = {pSet->id,pSet->Ia,pSet->Ib,pSet->Ic};
    Int32 i;
    for(i = 0;i < 4;i++)
    {
        memcpy(bufT,msg[i],strlen(msg[i]) +1 );
        foc_int2str(val[i],bufT + strlen(bufT),10);
        foc_msgTxBufWrite(bufT,strlen(bufT));
    }
    foc_msgTxBufWrite("\r\n",2);
    return 0;
}

 /*********************************************************************
 * @fn      printTheta
 *
 * @brief   打印当前电角度
 *
 * @param   theta 电角度， Ia 电流
 *
 * @return  None
 */
Int32 printTheta(_iq theta,_iq Ia)
{
    float ch[2];
    char  tail[4] = {0x00,0x00,0x80,0x7f}; 
    ch[0] = (float)theta;
    ch[1] = (float)Ia;
    foc_msgTxBufWrite((char *)ch,sizeof(float) * 2);
    foc_msgTxBufWrite((char *)tail,4);
    //foc_msgTxBufWrite("\r\n",2);
}

 /*********************************************************************
 * @fn      printData
 *
 * @brief   打印数据
 *
 * @param   theta 电角度， Ia 电流
 *
 * @return  None
 */
Int32 printData(float *ch,Int len)
{
    char  tail[4] = {0x00,0x00,0x80,0x7f}; 
    foc_msgTxBufWrite((char *)ch,sizeof(float) * len);
    foc_msgTxBufWrite((char *)tail,4);
}

 /*********************************************************************
 * @fn      foc_msgTxBufWrite
 *
 * @brief   写log到msgTxBuf里.
 *
 * @param   pBuffer - log地址. size - 待发送log的长度
 *
 * @return  None
 */
void foc_msgTxBufWrite(char *pBuffer, int size)
{
    bufSet *pTxbuf = &gLogDev.txBufObj;
    Int32 bufRight;           //写指针到写buf边界的距离
    if (!pBuffer || !pTxbuf->pWrite || !switchFlag)
    {
        return;
    }
    if (!gLogDev.txBufSemp)
    {
        return;
    }
    //避免多线程操作
    //xSemaphoreTake(gLogDev.txBufSemp,portMAX_DELAY);
    bufRight = pTxbuf->bufEnd - pTxbuf->pWrite;
    if (size < bufRight)
    {
        memcpy(pTxbuf->pWrite,pBuffer,size);
        pTxbuf->pWrite += size;
    }
    else 
    {
        memcpy(pTxbuf->pWrite,pBuffer,bufRight);
        pTxbuf->pWrite = pTxbuf->bufBegin;
        memcpy(pTxbuf->pWrite, pBuffer + bufRight, size - bufRight);
        pTxbuf->pWrite += (size - bufRight);
    }
    //xSemaphoreGive(gLogDev.txBufSemp);
}

/*********************************************************************
 * @fn      foc_msgRxBufWrite
 *
 * @brief   写数据到msgRxBuf里
 *
 * @param   
 *
 * @return  
 */
void foc_msgRxBufWrite(void)
{
    static uInt32 recved = 0;
    static uInt32 lastRecv = 0;
    uInt32 recvStatus;
    bufSet *pRxbuf = &gLogDev.rxBufObj;

    recvStatus = foc_recvMsg();
    if (recvStatus == lastRecv)
    {
        return;
    }
    if (recvStatus > lastRecv)
    {
        recved += (lastRecv + (LOG_RX_BUF_SIZE - recvStatus));
    }
    else 
    {
        recved += (lastRecv - recvStatus);
    }
    lastRecv = recvStatus;

    if (!pRxbuf->pRead)
    {
        return;
    }

    pRxbuf->wCount = recved;
    pRxbuf->pWrite = pRxbuf->bufBegin + (recved % LOG_RX_BUF_SIZE);

    if ((pRxbuf->pWrite > pRxbuf->pRead)&&(pRxbuf->wCount > pRxbuf->rCount + LOG_RX_BUF_SIZE))
    {
        if (pRxbuf->pWrite == pRxbuf->bufEnd)
        {
            pRxbuf->pRead = pRxbuf->bufBegin;
        }
        else 
        {
            pRxbuf->pRead = pRxbuf->pWrite + 1;
        }
        //丢失数据
        pRxbuf->rCount = pRxbuf->wCount - (LOG_RX_BUF_SIZE - 1);
    }
}

 /*********************************************************************
 * @fn      foc_msgRxBufRead
 *
 * @brief   从msgRxBuf里读数据，如果缓存区里数据 < bufLen,则读完缓存区
 *
 * @param   pBuffer - 读出的数据存放地址. bufLen - 要读的长度
 *
 * @return  成功返回读到数据长度，失败返回-1
 */
int foc_msgRxBufRead(char *pBuffer, int bufLen)
{
    bufSet *pRxbuf = &gLogDev.rxBufObj;
    int count = 0; //保存已读数据个数
    int canRead = 0; //可读长度
    int willRead = 0; //要读长度
    //read buf控制模块已初始化
    if (!pBuffer || !pRxbuf->pRead)
    {
        return -1;
    }
    //read buf信号量创建了
    if (!gLogDev.rxBufSemp)
    {
        return -1;
    }
    //判断rxBuf里面数据是否更新
    if (pRxbuf->pWrite == pRxbuf->pRead)
    {
        return 0;
    }

    //避免多线程操作
    xSemaphoreTake(gLogDev.rxBufSemp,portMAX_DELAY);
    //计算可读长度
    if(pRxbuf->pRead > pRxbuf->pWrite)
    {
        canRead = (pRxbuf->bufEnd - pRxbuf->pRead) + (pRxbuf->pWrite - pRxbuf->bufBegin);
    }
    else 
    {
        canRead = pRxbuf->pWrite - pRxbuf->pRead;
    }
    willRead = bufLen > canRead ? canRead : bufLen;
    //在处理读指针大于写指针的情况
    if (pRxbuf->pRead > pRxbuf->pWrite)
    {
        if ((pRxbuf->bufEnd - pRxbuf->pRead) > willRead)
        {
            memcpy(pBuffer, pRxbuf->pRead,willRead);
            count = willRead;
            pRxbuf->rCount += willRead;
            pRxbuf->pRead += willRead;
        }
        else 
        {
            memcpy(pBuffer, pRxbuf->pRead, pRxbuf->bufEnd - pRxbuf->pRead);
            count = pRxbuf->bufEnd - pRxbuf->pRead;
            pRxbuf->rCount += count;
            pRxbuf->pRead = pRxbuf->bufBegin;
        }
    }

    memcpy(pBuffer,pRxbuf->pRead, willRead - count);
    pRxbuf->pRead += (willRead - count);
    pRxbuf->rCount += (willRead - count);
    count += (willRead - count);
    
    xSemaphoreGive(gLogDev.rxBufSemp);

    return count;
}

/*********************************************************************
 * @fn      foc_sendMsgTxBuf
 *
 * @brief   发送msgTxBuf里的内容.
 *
 * @param   pBuffer - log地址. size - 待发送log的长度
 *
 * @return  None
 */
static void foc_sendMsgTxBuf(void)
{
    bufSet *pTxbuf = &gLogDev.txBufObj;
    Int32 sendLen;           //读指针到写指针的距离
    uInt8     *pWrite;
    if (!pTxbuf->pWrite || !pTxbuf->pRead)
    {
        return;
    }
    pWrite = pTxbuf->pWrite;
    sendLen = pWrite - pTxbuf->pRead;
    if (!sendLen)
    {
        return;
    }
    if (!gLogDev.txBufSemp)
    {
        return;
    }
    xSemaphoreTake(gLogDev.txBufSemp,portMAX_DELAY);
    if (sendLen > 0)
    {
        logSend(pTxbuf->pRead,sendLen);
        pTxbuf->pRead += sendLen;
    }
    else 
    {
        sendLen = pTxbuf->bufEnd - pTxbuf->pRead;
        logSend(pTxbuf->pRead,sendLen);
        pTxbuf->pRead = pTxbuf->bufBegin;

        sendLen = pWrite - pTxbuf->pRead;
        logSend(pTxbuf->pRead,sendLen);
        pTxbuf->pRead += sendLen;
    }
    xSemaphoreGive(gLogDev.txBufSemp);
}
/*********************************************************************
 * @fn      thread_interact
 *
 * @brief   与外界交换的线程，
 *              void
 *
 * @return  FUNC_SOK，成功  FUNC_FAIL，失败
 *          
 */
Int thread_interact(void *arg)
{
    logSet *pLogDev = &gLogDev;
    uInt32 count = 0;
    workLed_ *pLed;
    DMA_Channel_TypeDef *pDMA1_Channel6 = (DMA_Channel_TypeDef *)DMA1_Channel6;
    USART_TypeDef *USARTx = USART2;


    printf("%s  -- start\n",__FUNCTION__);

    pLed = workLedCreate();

    pLogDev->txBufObj.bufBegin = msgTxBuf;
    pLogDev->txBufObj.len = sizeof(msgTxBuf);
    pLogDev->txBufObj.bufEnd = msgTxBuf + pLogDev->txBufObj.len;
    pLogDev->txBufObj.pRead = pLogDev->txBufObj.pWrite = msgTxBuf;
    
    pLogDev->txBufSemp = xSemaphoreCreateBinary();
    if (!pLogDev->txBufSemp)
    {
        PRINT_EER("create pLogDev->txBufSemp fail\n");
        goto err;
    }
    xSemaphoreGive(gLogDev.txBufSemp);

    pLogDev->rxBufObj.bufBegin = msgRxBuf;
    pLogDev->rxBufObj.len = sizeof(msgRxBuf);
    pLogDev->rxBufObj.bufEnd = msgRxBuf + pLogDev->rxBufObj.len;
    pLogDev->rxBufObj.pRead = pLogDev->rxBufObj.pWrite = msgRxBuf;
    pLogDev->rxBufSemp = xSemaphoreCreateBinary();
    if (!pLogDev->rxBufSemp)
    {
        PRINT_EER("create pLogDev->rxBufSemp fail\n");
        goto err1;
    }
    xSemaphoreGive(gLogDev.rxBufSemp);

    switchFlag = 1;
    uartRecv(msgRxBuf,sizeof(msgRxBuf));
    while(1)
    {
        if (count & 0x80)
        {
            pLed->setupLed();
        }
        else 
        {
            pLed->downLed();
        }
        if (count & 0x20)
        {
            foc_sendMsgTxBuf();
        }
        Delay_Ms(1);
        count++;
    }
    vTaskDelete(NULL);
    return FUNC_SOK;
err1:
    vSemaphoreDelete(pLogDev->txBufSemp);
err:
    vTaskDelete(NULL);
    return FUNC_FAIL;
}





